//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see http://www.gnu.org/licenses/.
// 

#include "MACLayer.h"
#include "message_m.h"
#include "message_k.h"

Define_Module(MACLayer)
;

void MACLayer::initialize()
{
	// TODO - Generated method body
	buffer_head = 0;
	buffer_tail = 0;
	endSimuFlag = false;
}

void MACLayer::handleMessage(cMessage *msg)
{
	EV<< "MACLayer received message" << endl;
	switch(msg->getKind())
	{
		case DataMsgKind:
			send(msg, "sinkDataOut");
		break;
		case RequestSendDataMsgKind:
			if(buffer_head != buffer_tail)
			{
				DataFromGeneratorMsg *dataMsg = check_and_cast<DataFromGeneratorMsg *>(msgBuffer[buffer_head]);
				MACAssignedDataMsg *madMsg = new MACAssignedDataMsg(NULL, MACAssignedDataMsgKind);

				madMsg->setNeedSend(true);
				madMsg->setId(dataMsg->getId());
				madMsg->setSenderId(dataMsg->getSenderId());
				madMsg->setReceiverId(dataMsg->getReceiverId());
				madMsg->setDataPacketSize(dataMsg->getDataPacketSize());
				madMsg->setDataSendingTime(dataMsg->getDataSendingTime());

				buffer_head = (buffer_head + 1) % MAX_MESSAGE_BUFFER_SIZE;
				send(madMsg, "lowerDataPort$o");
			}
			else if(endSimuFlag)
			{
				EndSimuMsg *esMsg = new EndSimuMsg(NULL, EndSimuMsgKind);
				send(esMsg, "lowerControlPort$o");
			}
			else
			{
				MACAssignedDataMsg *madMsg = new MACAssignedDataMsg(NULL, MACAssignedDataMsgKind);
				madMsg->setNeedSend(false);

				send(madMsg, "lowerDataPort$o");
			}


		break;
		case RequestChannelInfoMsgKind:
			send(msg, "protocolControlPort$o");
			break;
		case DataFromGeneratorMsgKind:
			if (dynamic_cast<DataFromGeneratorMsg *> (msg) != NULL)
			{
				DataFromGeneratorMsg *dataMsg = check_and_cast<DataFromGeneratorMsg *>(msg);
				RequestReceivedConfirmMsg *confirmMsg =
						new RequestReceivedConfirmMsg(NULL, RequestReceivedConfirmMsgKind);
				confirmMsg->setConfirm(false);
				confirmMsg->setId(dataMsg->getId());
				if ((buffer_tail + 1) % MAX_MESSAGE_BUFFER_SIZE != buffer_head)
				{
					msgBuffer[buffer_tail] = msg;
					buffer_tail = (buffer_tail + 1) % MAX_MESSAGE_BUFFER_SIZE;
					confirmMsg->setConfirm(true);
				}
				else
				{
					confirmMsg->setConfirm(false);
				}
				send(confirmMsg, "generatorControlPort$o");
			}
			break;
		case ChannelInfoMsgKind:
			send(msg, "lowerControlPort$o");
			break;
		case EndSimuMsgKind:
			endSimuFlag = true;
			delete msg;
			break;
		case DeleteHostMsgKind:
			send(msg, "protocolControlPort$o");
			break;
		case DataTransmitInfoMsgKind:
			send(msg, "sinkDataOut");
			break;
	}
}
